/* Copyright (C) 2008  Romolo Camplani, Marco Fortunato, Marco Marelli, Guido Rota, Fabio A. Schreiber et al.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.dei.perla.component;

import org.dei.perla.utils.logger.ILogger;
import org.dei.perla.utils.logger.LogRecord;
import org.dei.perla.utils.logger.LogRecord.Type;
import org.dei.perla.utils.logger.LogRecord.Verbosity;

/**
 * Classe base per tutti i componenti (AdapterSrv, Channel, ecc.).
 * Ciascuno di essi ha un nome univoco che lo identifica ed un insieme di Logger 
 * registrati per ricevere le notifiche dal componente stesso.
 */
public abstract class Component implements Startable {
	
	/**
	 * Stringa che identifica la singola istanza del componente
	 */
	private String pName;

	/**
	 * Stringa che identifica il tipo di componente (es: AdapterSrv, Channel, ecc.)
	 */
	private String pType;

	/**
	 * Indica se il componente è attualmente avviato
	 */
	private boolean pStarted;

	/**
	 * Collection dei loggers registrati a ricevere le notifiche dal componente
	 */
	private java.util.ArrayList<ILogger> pLoggers;

	/**
	 * Costruttore
	 */
	public Component(String parName) {

		// Inizializza le variabili
		this.pName = parName;
		this.pStarted = false;

		// Istanzia la collection dei logger registrati
		this.pLoggers = new java.util.ArrayList<ILogger>();
	}

	/**
	 * Restituisce il nome del componente
	 */
	public String getName() {
		return this.pName;
	}

	/* (non-Javadoc)
	 * @see org.dei.perla.component.Startable#start()
	 */
	public void start() {
		this.setStarted(true);
	}

	/* (non-Javadoc)
	 * @see org.dei.perla.component.Startable#stop()
	 */
	public void stop() {
		this.setStarted(false);
	}

	/**
	 * Imposta il flag che indica se il componente è avviato
	 * @param parStarted Flag per avviare/fermare il componente. Se è vero avvia il componente, se è falso lo ferma.
	 */
	protected void setStarted(boolean parStarted) {

		String tMessage;

		// Se lo stato del componente è cambiato..
		if (this.pStarted != parStarted) {

			// .. aggiorna il flag di avviato
			this.pStarted = parStarted;

			// .. e inserisce un messaggio nel log
			if (this.pStarted)
				tMessage = "Componente avviato";
			else
				tMessage = "Componente arrestato";
			this.loggerNotify(Type.Information, tMessage, Verbosity.High);
		}
	}

	/* (non-Javadoc)
	 * @see org.dei.perla.component.Startable#isStarted()
	 */
	public boolean isStarted() {

		return this.pStarted;
	}

	/**
	 * Registra un nuovo Logger per ricevere le notifiche del componente
	 */
	public void loggerAttach(ILogger parLogger) {

		synchronized (this.pLoggers) {
			if ((parLogger != null) && (!this.pLoggers.contains(parLogger)))
				this.pLoggers.add(parLogger);
		}
	}

	/**
	 * Registra un nuovo Logger per ricevere le notifiche del componente
	 */
	public void loggerAttach(Component parComponent) {

		synchronized (this.pLoggers) {
			if (parComponent != null) {
				synchronized (parComponent.pLoggers) {
					for (ILogger tRegisteredLogger : parComponent.pLoggers)
						this.loggerAttach(tRegisteredLogger);
				}
			}
		}
	}

	/**
	 * Deregistra un Logger già registrato 
	 */
	public void loggerDetach(ILogger parLogger) {

		synchronized (this.pLoggers) {
			if ((parLogger != null) && (this.pLoggers.contains(parLogger)))
				this.pLoggers.remove(parLogger);
		}
	}

	/**
	 * Deregistra tutti i logger registrati
	 */
	public void loggerDetachAll() {

		synchronized (this.pLoggers) {
			this.pLoggers.clear();
		}
	}

	/**
	 * Notifica a tutti i logger registrati un messaggio
	 * @param parMessageType Tipo del messaggio
	 * @param parMessage Descrizione del messaggio
	 * @param parVerbosity Verbosità associata al messaggio
	 */
	protected void loggerNotify(Type parMessageType, String parMessage,
			Verbosity parVerbosity) {

		LogRecord tLogRecord = null;

		synchronized (this.pLoggers) {

			// Se c'è almeno un Logger registrato..
			if (this.pLoggers.size() > 0) {

				// .. crea il messaggio di log
				tLogRecord = new LogRecord(this.pType, this.pName,
						parMessageType, parMessage, "", parVerbosity);

				// .. e lo aggiunge a tutti i logger registrati
				for (ILogger tRegisteredLogger : this.pLoggers)
					tRegisteredLogger.add(tLogRecord);
			}
		}
	}

	/**
	 * Notifica a tutti i logger registrati un messaggio
	 * @param parMessageType Tipo del messaggio
	 * @param parMessage     Descrizione del messaggio
	 * @param parDetails     Descrizione dettagliata del messaggio
	 * @param parVerbosity   Verbosità associata al messaggio
	 */
	protected void loggerNotify(Type parMessageType, String parMessage,
			String parDetails, Verbosity parVerbosity) {

		LogRecord tLogRecord = null;

		synchronized (this.pLoggers) {

			// Se c'è almeno un Logger registrato..
			if (this.pLoggers.size() > 0) {

				// .. crea il messaggio di log
				tLogRecord = new LogRecord(this.pType, this.pName,
						parMessageType, parMessage, parDetails, parVerbosity);

				// .. e lo aggiunge a tutti i logger registrati
				for (ILogger tRegisteredLogger : this.pLoggers)
					tRegisteredLogger.add(tLogRecord);
			}
		}
	}

}
